﻿#pragma once

#include "coroutine/coroutine.h"
#include "coroutine/detail/timer.h"
#include "rpc_defines.h"
#include "rpc_singleton.h"
#include "rpc_transport.h"
#include <limits>
#include <list>
#include <memory>
#include <unordered_map>
#include <vector>

namespace kratos {
namespace service {
class ServiceContext;
}
} // namespace kratos

namespace rpc {

class Stub;
class StubImpl;
class StubCall;
class StubFactory;
class Rpc;
class RpcImpl;
class StubManagerImpl;
class InterfaceDescriptor;

using ServiceList = std::vector<StubPtr>;

// 限流器
class Limiter {
public:
  virtual ~Limiter() {}
  // 是否被限流
  virtual auto is_limit() -> bool = 0;
};

// Stub manager interface
class StubManager {
public:
  virtual ~StubManager() {}
  // Add a service stub
  // @param stub The stub need to enroll
  // @retval New stub pointer
  virtual StubPtr addService(StubPtr stub) = 0;
  // Find or create a new stub by service UUID
  // @param uuid service UUID
  // @retval New stub pointer
  virtual StubPtr getServiceByUUID(ServiceUUID uuid) = 0;
  // Find service by service instance ID
  // @param id service instance ID
  // @retval New stub pointer
  virtual StubPtr getServiceByID(ServiceID id) = 0;
  // Switch all stub with service UUID from current status to target status
  // @param uuid service UUID
  virtual void setStatus(ServiceUUID uuid, StubStatus status) = 0;
  // Invoked by Rpc::update
  // @param ms current timestamp in millionseconds
  virtual void update(std::time_t ms = 0) = 0;
  // Returns services by service UUID
  virtual ServiceList &getMutableServiceMapUnsafe(ServiceUUID uuid) = 0;
  virtual void removeAllServiceByUUID(ServiceUUID uuid) = 0;
  // Cleanup
  virtual void cleanup() = 0;
  // Set the limit of calling rate per second
  virtual void setLimiter(ServiceUUID uuid, Limiter* limiter_ptr) = 0;
};

// Stub manager
class StubManagerImpl : public StubManager {
  // Service instances
  struct ServiceInstances {
    ServiceList services;   ///< service instance list
    std::size_t index{0};   ///< current index
  };
  using StubImplPtr = std::shared_ptr<Stub>;
  using ServiceMap = std::unordered_map<ServiceID, StubPtr>;
  using LimiterMap = std::unordered_map<ServiceUUID, Limiter*>;
  using StubTypeUUIDMap = std::unordered_map<ServiceUUID, ServiceInstances>;
  StubTypeUUIDMap typeMap_; ///< {ServiceID, ServiceInstances}
  LimiterMap limiter_map_;  ///< {ServiceUUID, LimiterPtr}
  ServiceMap serviceMap_;   ///< {ServiceID, StubPtr}
  ServiceID serviceID_{1};  ///< Service instance starter ID
  RpcImpl *rpc_{nullptr};   ///< Rpc instance

public:
  // ctor
  // @param rpc Rpc instance
  StubManagerImpl(RpcImpl *rpc);
  // dtor
  virtual ~StubManagerImpl();
  // Add a service stub
  // @param stub The stub need to enroll
  // @retval New stub pointer
  virtual StubPtr addService(StubPtr stub) override;
  // Find or create a new stub by service UUID
  // @param uuid service UUID
  // @retval New stub pointer
  virtual StubPtr getServiceByUUID(ServiceUUID uuid) override;
  // Find service by service instance ID
  // @param id service instance ID
  // @retval New stub pointer
  virtual StubPtr getServiceByID(ServiceID id) override;
  // Switch all stub with service UUID from current status to target status
  // @param uuid service UUID
  virtual void setStatus(ServiceUUID uuid, StubStatus status) override;
  // Invoked by Rpc::update
  // @param ms current timestamp in millionseconds
  virtual void update(std::time_t ms = 0) override;
  // Returns services by service UUID
  virtual ServiceList &getMutableServiceMapUnsafe(ServiceUUID uuid) override;
  virtual void removeAllServiceByUUID(ServiceUUID uuid) override;
  // 更新所有指定UUID的Stub
  void resetAllStub(ServiceUUID uuid, BundleEntryFunc func);
  // Cleanup
  virtual void cleanup() override;
  virtual void setLimiter(ServiceUUID uuid, Limiter* limiter_ptr) override;
};

// Stub interface
class Stub {
public:
  virtual ~Stub() {}
  // Returns service UUID
  virtual ServiceUUID getUUID() = 0;
  // Call service
  // @param callPtr StubCall pointer
  virtual void call(StubCallPtr callPtr) = 0;
  // Returns current service name
  virtual const char *getServiceName() = 0;
  // Returns method name by method ID
  virtual const char *getMethodName(MethodID methodID) = 0;
  // Invoked by framework after finish construction
  virtual bool onAfterFork(rpc::Rpc *rpc) = 0;
  // Invoked by framework before destruction
  virtual bool onBeforeDestory(rpc::Rpc *rpc) = 0;
  // Re-setup new entry function for dynamic loading service
  virtual bool reset(BundleEntryFunc entryFunc, rpc::Rpc *rpc) = 0;
  // Tick for stub
  virtual void tick(std::time_t ms) = 0;
  virtual void update(std::time_t ms) = 0;
  virtual void setStatus(StubStatus status) = 0;
  virtual bool isStarted() = 0;
  virtual bool isLimited() = 0;
};

// The stub wrapper for service

class StubImpl : public Stub {
protected:
  StubStatus status_{StubStatus::RESOLVED}; ///< Stub status
  StubType type_{StubType::SINGLE};         ///< Stub factory type
  ServiceID serviceID_{INVALID_SERVICE_ID}; ///< Service instance ID
  using CallQueue = std::list<StubCallPtr>;
  CallQueue callQueue_;           ///< The queue of pending call
  int reference_{0};              ///< The reference count of concurrent call
  StubFactory *factory_{nullptr}; ///< Stub factory pointer
  BundleEntryFunc entryFunc_{nullptr}; ///< For dynamic loading service
  kratos::service::ServiceContext *ctx_{nullptr}; ///< context
  RpcImpl *rpc_{nullptr};                         ///< Rpc instance
  bool started_{false};                           ///< Is started?
  Limiter* limiter_ptr_; ///< The limits of calling rate per second for
                           ///< service of same type

public:
  // dtor
  virtual ~StubImpl();
  // Setup stub type
  void setType(StubType type);
  // Returns stub type
  StubType getType();
  // Returns service ID
  ServiceID getServiceID();
  // Setup service instance ID
  void setServiceID(ServiceID serviceID);
  // Invoked by StubManager::update()
  virtual void update(std::time_t ms) override;
  // Increase reference count of concurrent call
  void incref();
  // Decrease reference count of concurrent call
  void decref();
  // Is zero reference count of concurrent call?
  bool zeroref();
  // Setup entry function for dynamic loading service
  void setEntryFunc(BundleEntryFunc entryFunc);
  // Returns entry function
  BundleEntryFunc getEntryFunc();
  // Setup service status
  virtual void setStatus(StubStatus status) override;
  virtual bool isStarted() override;
  virtual bool isLimited() override;
  // Returns service status
  StubStatus getStatus();
  // Setup stub factory
  void setFactory(StubFactory *factory);
  // Returns stub factory
  StubFactory *getFactory();
  // Setup context
  void setContext(kratos::service::ServiceContext *ctx);
  // Query context
  kratos::service::ServiceContext *getContext();
  // Setup Rpc instance
  void setRpc(Rpc *rpc);
  // Returns Rpc instance
  Rpc *getRpc();
  // Set limits
  void setLimiter(Limiter* limiter_ptr);

private:
  // Process a Method call
  void callStub(StubCallPtr &stubCall);
  // Read given bytes and process a method call
  // @param transport Transportation
  // @param bytes how many bytes need to read from stream
  // @param header RpcCallRequestHeader reference
  void callStub(TransportPtr &transport, int bytes,
                const RpcCallRequestHeader &header);
  // Read given bytes and process a method call
  // @param transport Transportation
  // @param bytes how many bytes need to read from stream
  // @param header RpcProxyCallRequestHeader reference
  void callStubProxy(TransportPtr &transport, int bytes,
                     const RpcProxyCallRequestHeader &header);
  // Process a method in a coroutine
  void callCoro(StubCallPtr &stubCall);
  // Process a method in current thread/coroutine
  void callNormal(StubCallPtr &stubCall);

  friend class RpcImpl;
  friend class StubFactory;
};

// Stub call interface
class StubCall {
public:
  virtual ~StubCall() {}
  virtual void finish() = 0;
  // Returns Argument serialized data and size
  // @param [OUT] size data size
  // @return serialized data pointer
  virtual const char *getData(int &size) = 0;
  // Returns method ID
  virtual MethodID getMethodID() = 0;
  // Returns proxy call instance ID
  virtual CallID getCallID() = 0;
  // Returns transportation
  virtual TransportPtr getTransport() = 0;
  // Returns required service instance ID
  virtual ServiceID getServiceID() = 0;
  // Returns service UUID
  virtual ServiceUUID getServiceUUID() = 0;
  // Service not found
  virtual void notFound() = 0;
  // Returns global index
  virtual GlobalIndex getGlobalIndex() = 0;
  // Returns Rpc instance
  virtual Rpc *getRpc() = 0;
  // Returns call instance ID
  virtual StubCallID getStubCallID() = 0;
  // Is coro mode?
  virtual bool isCoroMode() = 0;
  virtual const std::string &getTraceID() = 0;
  virtual void setTraceID(const std::string &traceID) = 0;
  virtual std::uint64_t getSpanID() = 0;
  virtual void setSpanID(std::uint64_t spanID) = 0;
  virtual void setParentSpanID(std::uint64_t parentSpanID) = 0;
  virtual std::uint64_t getParentSpanID() = 0;
};

// A method call
class StubCallImpl : public StubCall {
  StubCallID stubCallID_{INVALID_STUB_CALL_ID}; ///< Stub call instance ID
  CallID callID_{INVALID_CALL_ID};          ///< Remote proxy call instance ID
  MethodID methodID_{INVALID_METHOD_ID};    ///< Method ID
  ServiceID serviceID_{INVALID_SERVICE_ID}; ///< Service instance ID
  ServiceUUID serviceUUID_{INVALID_SERVICE_UUID};        ///< Service UUID
  coroutine::CoroID coroID_{coroutine::INVALID_CORO_ID}; ///< Coroutine ID
  TransportPtr transport_{nullptr};                      ///< Transportation
  TimerHandle timerHandle_{nullptr};                     ///< Timer handle
  char *data_{nullptr};  ///< Method's argument serialized data
  int dataSize_{0};      ///< Argument serialized data size
  bool finished_{false}; ///< Call has finished or not
  std::time_t startCallTime_{
      0}; ///< The start time in microseconds to call method
  GlobalIndex globalIndex_{INVALID_GLOBAL_INDEX}; ///< Global index
  RpcImpl *rpc_{nullptr};                         ///< Rpc instance
  std::string traceID_;
  std::uint64_t spanID_{0};
  std::uint64_t parentSpanID_{0};

public:
  // dtor
  virtual ~StubCallImpl();
  // Finish call
  virtual void finish() override;
  // Returns Argument serialized data and size
  // @param [OUT] size data size
  // @return serialized data pointer
  virtual const char *getData(int &size) override;
  // Returns method ID
  virtual MethodID getMethodID() override;
  // Returns proxy call instance ID
  virtual CallID getCallID() override;
  // Returns transportation
  virtual TransportPtr getTransport() override;
  // Returns required service instance ID
  virtual ServiceID getServiceID() override;
  // Returns service UUID
  virtual ServiceUUID getServiceUUID() override;
  // Service not found
  virtual void notFound() override;
  // Returns global index
  virtual GlobalIndex getGlobalIndex() override;
  // Returns Rpc instance
  virtual Rpc *getRpc() override;
  // Returns call instance ID
  virtual StubCallID getStubCallID() override;
  // Is coro mode?
  virtual bool isCoroMode() override;

  virtual const std::string &getTraceID() override;
  virtual void setTraceID(const std::string &traceID) override;
  virtual std::uint64_t getSpanID() override;
  virtual void setSpanID(std::uint64_t spanID) override;
  virtual void setParentSpanID(std::uint64_t parentSpanID) override;
  virtual std::uint64_t getParentSpanID() override;

protected:
  // Is call finished?
  bool isFinished();
  // Setup transportation
  void setTransport(TransportPtr transport);
  // Setup time handle
  void setTimerHandle(TimerHandle timerHandle);
  // Returns timer handle
  TimerHandle getTimerHandle();
  // Setup coroutine ID
  void setCoroID(coroutine::CoroID coroID);
  // Returns coroutine ID
  coroutine::CoroID getCoroID();
  // Setup proxy call instance ID
  void setCallID(CallID callID);
  // Setup method ID
  void setMethodID(MethodID methodID);
  // Setup required service instance ID
  void setServiceID(ServiceID serviceID);
  // Setup service UUID
  void setServiceUUID(ServiceUUID serviceUUID);
  // Setup call instance ID
  void setStubCallID(StubCallID stubCallID);
  // Read from transport and save data
  void setData(TransportPtr &transport, int size);
  // Start execution timer
  bool startExecTimer();
  // Stop execution timer
  void stopExecTimer();
  // Cleanup
  void clean();
  // Set start time
  void setStartTime(std::time_t ms);
  // Get start time
  std::time_t getStartTime();
  // Set global index
  void setGlobalIndex(GlobalIndex globalIndex);
  // Setup Rpc instance
  void setRpc(Rpc *rpc);
  friend class RpcImpl;
  friend class TransportGuard;
  friend class StubImpl;
  friend class StubCallManagerImpl;
};

// Stub call manager interface
class StubCallManager {
public:
  virtual ~StubCallManager() {}
  // Main loop
  // @param ms current timestamp in millionsecond
  virtual void update(std::time_t ms) = 0;
  // Add a stub call
  // @param call new stub call
  virtual void add(StubCallPtr call) = 0;
  // Find stub call
  // @param id Stub call ID
  virtual StubCallPtr get(StubCallID id) = 0;
  // Destory stub call
  virtual void destroy(StubCallID id) = 0;
  // Remove all stub call by service ID
  virtual void removeByServiceID(ServiceID serviceID) = 0;
  // Returns Timer instance
  virtual TimerBase *getTimer() = 0;
  // Cleanup
  virtual void cleanup() = 0;
};

// Stub call manager
class StubCallManagerImpl : public StubCallManager {
  using StubCallImplPtr = std::shared_ptr<StubCallImpl>;
  using CallMap = std::unordered_map<std::uint32_t, StubCallImplPtr>;
  CallMap *callMap_{nullptr}; ///< Stub call map
  StubCallID callID_{1};      ///< Call instance starter ID
  RpcImpl *rpc_{nullptr};     ///< Rpc instance
  Timer timer_;               ///< Timer manager

public:
  // ctor
  // @param rpc Rpc instance
  StubCallManagerImpl(RpcImpl *rpc);
  virtual ~StubCallManagerImpl();
  // Main loop
  // @param ms current timestamp in millionsecond
  virtual void update(std::time_t ms) override;
  // Add a stub call
  // @param call new stub call
  virtual void add(StubCallPtr call) override;
  // Find stub call
  // @param id Stub call ID
  virtual StubCallPtr get(StubCallID id) override;
  // Destory stub call
  virtual void destroy(StubCallID id) override;
  // Remove all stub call by service ID
  virtual void removeByServiceID(ServiceID serviceID) override;
  // Returns Timer instance
  virtual TimerBase *getTimer() override;
  // Cleanup
  virtual void cleanup() override;
};

// The base class for stub factory
class StubFactory {
public:
  // dtor
  virtual ~StubFactory() {}
  // Create a new stub
  virtual Stub *create(kratos::service::ServiceContext *ctx = nullptr) = 0;
  // Is a dynamic loading stub
  virtual bool isDynamic() = 0;
  // 当Stub被销毁时调用
  virtual void onStubDestroy() = 0;
  // 获取版本
  virtual const std::string &getVersion() = 0;
  // 获取类型
  virtual StubType getType() = 0;
};

// Dynamic loading factory
class StubFactoryDynamic : public StubFactory {
protected:
  struct ClassInfo {
    ModuleHandle loadHandle{INVALID_MODULE_HANDLE}; ///< Shared object handle
    std::string entryName{
        DEFAULT_ENTRY_NAME}; ///< Shared object entry function name
    BundleEntryFunc entryFunc{
        nullptr}; ///< Shared object entry function address
    std::string versionName{
        DEFAULT_VERSION_NAME}; ///< Shared object version function name
    BundleVersionFunc versionFunc{
        nullptr}; ///< Shared object version function address
    std::string buildName{
        DEFAULT_BUILD_NAME}; ///< Shared object build function name
    BundleBuildFunc buildFunc{
        nullptr}; ///< Shared object build function address
    BundleInterfaceDescriptorFunc descriptorFunc{
        nullptr};           ///< Interface descriptor function address
    std::string bundlePath; ///< Bundle file path
    int refCnt{0};          ///< Reference count
    operator bool() { return (loadHandle != INVALID_MODULE_HANDLE); }
  };
  ClassInfo curClass_; ///< Current dynamic class
  using ClassList = std::list<ClassInfo>;
  ClassList classList_; ///< All ever loaded class
  std::string version_; ///< Version string

public:
  // dtor
  virtual ~StubFactoryDynamic();
  virtual bool isDynamic() override;
  virtual void unload() = 0;
  virtual int onStatusChange(Rpc *rpc, StubStatus status) = 0;
  virtual void onStubDestroy() override;
  virtual const std::string &getVersion() override;
  // Returns shared object entry function
  BundleEntryFunc getEntryFunc();
  // Load service from file system
  bool load(Rpc *rpc, const std::string &bundlePath);
  // Unload shared object
  void unloadClass(bool all = false);

private:
  // Unload service
  bool unload(ClassInfo &ci);
};

class StubFactoryImpl : public StubFactory {
  StubType type_{StubType::SINGLE};
  std::string version_; ///< Version string

public:
  StubFactoryImpl(StubType type);
  virtual ~StubFactoryImpl() {}
  virtual bool isDynamic() override;
  virtual void onStubDestroy();
  virtual const std::string &getVersion() override;
  void setVersion(const std::string &version);
};

class StubFactoryDynamicImpl : public StubFactoryDynamic {
  StubType type_{StubType::SINGLE};

public:
  StubFactoryDynamicImpl(StubType type);
  virtual ~StubFactoryDynamicImpl() {}
};

template <typename T> class StubFactorySingleT : public StubFactoryImpl {
  StubImpl *stub_{nullptr};

public:
  StubFactorySingleT(std::size_t) : StubFactoryImpl(StubType::SINGLE) {}
  virtual ~StubFactorySingleT() {}
  virtual Stub *
  create(kratos::service::ServiceContext *ctx = nullptr) override {
    if (!stub_) {
      stub_ = new T();
      stub_->setFactory(this);
      stub_->setType(StubType::SINGLE);
      stub_->setContext(ctx);
    }
    return stub_;
  }
  virtual StubType getType() override { return StubType::SINGLE; }
};

template <typename T>
class StubFactorySingleDynamicT : public StubFactoryDynamicImpl {
  StubImpl *stub_{nullptr};

public:
  StubFactorySingleDynamicT(std::size_t)
      : StubFactoryDynamicImpl(StubType::SINGLE) {}
  virtual ~StubFactorySingleDynamicT() {}
  virtual Stub *
  create(kratos::service::ServiceContext *ctx = nullptr) override {
    if (!stub_) {
      stub_ = new T();
      stub_->setFactory(this);
      stub_->setEntryFunc(getEntryFunc());
      stub_->setType(StubType::SINGLE);
      stub_->setContext(ctx);
    }
    return stub_;
  }

  virtual int onStatusChange(Rpc *rpc, StubStatus status) override {
    if (stub_) {
      stub_->setStatus(status);
    }
    return 1;
  }

  virtual void unload() override { stub_ = nullptr; }

  virtual StubType getType() override { return StubType::SINGLE; }
};

template <typename T> class StubFactoryReentrantT : public StubFactoryImpl {
  StubImpl *stub_{nullptr};

public:
  StubFactoryReentrantT(std::size_t) : StubFactoryImpl(StubType::REENTRANT) {}
  virtual ~StubFactoryReentrantT() {}
  virtual Stub *
  create(kratos::service::ServiceContext *ctx = nullptr) override {
    if (!stub_) {
      stub_ = new T();
      stub_->setFactory(this);
      stub_->setType(StubType::REENTRANT);
      stub_->setContext(ctx);
    }
    return stub_;
  }
  virtual StubType getType() override { return StubType::REENTRANT; }
};

template <typename T>
class StubFactoryReentrantDynamicT : public StubFactoryDynamicImpl {
  StubImpl *stub_{nullptr};

public:
  StubFactoryReentrantDynamicT(std::size_t)
      : StubFactoryDynamicImpl(StubType::REENTRANT) {}
  virtual ~StubFactoryReentrantDynamicT() {}
  virtual Stub *
  create(kratos::service::ServiceContext *ctx = nullptr) override {
    if (!stub_) {
      stub_ = new T();
      stub_->setFactory(this);
      stub_->setEntryFunc(getEntryFunc());
      stub_->setType(StubType::REENTRANT);
      stub_->setContext(ctx);
    }
    return stub_;
  }

  virtual int onStatusChange(Rpc *rpc, StubStatus status) override {
    if (stub_) {
      stub_->setStatus(status);
    }
    return 1;
  }
  virtual void unload() override { stub_ = nullptr; }
  virtual StubType getType() override { return StubType::REENTRANT; }
};

template <typename T> class StubFactoryMultipleT : public StubFactoryImpl {
  std::size_t max_{MAX_SERVICE_COUNT};
  std::size_t curCount_{0};
  ServiceUUID serviceUUID_{INVALID_SERVICE_UUID};

public:
  StubFactoryMultipleT(std::size_t maxCount = MAX_SERVICE_COUNT)
      : StubFactoryImpl(StubType::MULTIPLE), max_(maxCount) {
    serviceUUID_ = T::uuid();
  }
  virtual ~StubFactoryMultipleT() {}
  virtual Stub *
  create(kratos::service::ServiceContext *ctx = nullptr) override {
    if (curCount_ < max_) {
      curCount_ += 1;
      auto stub = new T();
      stub->setFactory(this);
      stub->setType(StubType::MULTIPLE);
      stub->setContext(ctx);
      return stub;
    } else {
      return nullptr;
    }
  }
  virtual void onStubDestroy() override { curCount_ -= 1; }
  virtual StubType getType() override { return StubType::MULTIPLE; }
};

extern void onStubStatusChange(Rpc *rpc, StubStatus status,
                               ServiceUUID serviceUUID);

template <typename T>
class StubFactoryMultipleDynamicT : public StubFactoryDynamicImpl {
  std::size_t max_{MAX_SERVICE_COUNT};
  std::size_t curCount_{0};
  std::size_t unloadRef_{0};
  ServiceUUID serviceUUID_{INVALID_SERVICE_UUID};

public:
  StubFactoryMultipleDynamicT(std::size_t maxCount = MAX_SERVICE_COUNT)
      : StubFactoryDynamicImpl(StubType::MULTIPLE), max_(maxCount) {
    serviceUUID_ = T::uuid();
  }
  virtual ~StubFactoryMultipleDynamicT() {}
  virtual Stub *
  create(kratos::service::ServiceContext *ctx = nullptr) override {
    if (curCount_ < max_) {
      curCount_ += 1;
      auto stub = new T();
      stub->setFactory(this);
      stub->setEntryFunc(getEntryFunc());
      stub->setType(StubType::MULTIPLE);
      stub->setContext(ctx);
      return stub;
    } else {
      return nullptr;
    }
  }

  virtual int onStatusChange(Rpc *rpc, StubStatus status) override {
    onStubStatusChange(rpc, status, serviceUUID_);
    unloadRef_ = curCount_;
    return curCount_;
  }

  virtual void unload() override {
    unloadRef_ -= 1;
    if (unloadRef_ == 0) {
      unloadClass();
    }
  }

  virtual void onStubDestroy() override { curCount_ -= 1; }

  virtual StubType getType() override { return StubType::MULTIPLE; }
};

/**
 * Stub Creator
 */
class StubCreator {
  using StubFactoryMap =
      std::unordered_map<ServiceUUID, std::unique_ptr<StubFactory>>;
  StubFactoryMap factoryMap_; ///< StubFactory map

public:
  /**
   * ctor
   */
  StubCreator();
  /**
   * dtor
   */
  ~StubCreator();
  /**
   * Create service by UUID
   *
   * \param rpc Rpc instance
   * \param uuid service UUID
   * \param ctx ServiceContext instance
   * \return Stub pointer
   */
  StubPtr createService(Rpc *rpc, ServiceUUID uuid,
                        kratos::service::ServiceContext *ctx = nullptr);
  /**
   * Query service instance by service instance ID
   *
   * \param serviceID service instance ID
   * \return service instance
   */
  StubPtr getService(Rpc *rpc, ServiceID serviceID);
  /**
   * Is service existing?
   *
   * \param uuid service UUID
   * \return true or false
   */
  bool isExist(ServiceUUID uuid);
  /**
   * Register service factory
   *
   * \param maxCount Maximum service instance
   * \return true or false
   */
  template <typename T, typename FactoryT>
  bool registerServiceFactory(std::size_t maxCount = MAX_SERVICE_COUNT) {
    factoryMap_.emplace(T::uuid(), new FactoryT(maxCount));
    return true;
  }
  /**
   * Load bundle (.dll/.so) from bundlePath
   *
   * \param rpc Rpc instance
   * \param bundlePath bundle Path(Local disk)
   * \param noCreate Create one instance when finished loading
   * \param ctx ServiceContext instance
   * \return true or false
   */
  bool loadClass(Rpc *rpc, ServiceUUID uuid, const std::string &bundlePath,
                 bool noCreate = false,
                 kratos::service::ServiceContext *ctx = nullptr);
  /**
   * Unload bundle
   *
   * \param uuid Service UUID
   * \return true or false
   */
  bool unloadClass(ServiceUUID uuid);
  /**
   * Query StubFactory instance by service UUID
   *
   * \param uuid service UUID
   * \return StubFactory instance
   */
  StubFactory *getFactory(ServiceUUID uuid);
};

#define StubCreatorRef (*rpc::Singleton<rpc::StubCreator>::instance())

/**
 * 填充RPC返回包
 *
 * \param [OUT] rheader RpcRetHeader包头
 * \param stubCall RPC请求调用
 * \param serviceID 服务实例ID
 * \param errorID 错误码
 * \param bodySize RPC返回的消息体长度
 */
extern void buildHeader(RpcRetHeader &rheader, rpc::StubCallPtr stubCall,
                        rpc::ServiceID serviceID, rpc::ErrorID errorID,
                        std::uint32_t bodySize);

/**
 * 填充RPC返回包
 *
 * \param [OUT] rheader RpcRetHeader包头
 * \param callID RPC请求调用ID
 * \param serviceID 服务实例ID
 * \param errorID 错误码
 * \param bodySize RPC返回的消息体长度
 */
extern void buildHeader(RpcRetHeader &rheader, rpc::CallID callID,
                        rpc::ServiceID serviceID, rpc::ErrorID errorID,
                        std::uint32_t bodySize);

/**
 * 填充RPC代理返回包
 *
 * \param [OUT] rheader RpcProxyRetHeader包头
 * \param stubCall RPC请求调用
 * \param serviceID 服务实例ID
 * \param errorID 错误码
 * \param bodySize RPC返回的消息体长度
 */
extern void buildHeader(RpcProxyRetHeader &rheader, rpc::StubCallPtr stubCall,
                        rpc::ServiceID serviceID, rpc::ErrorID errorID,
                        std::uint32_t bodySize);

} // namespace rpc
